/*
 * Copyright 2012 Marsrutai.lt
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package lt.marsrutai.mobile.android.util;

import java.util.HashMap;
import java.util.Map;

import lt.marsrutai.mobile.android.manager.AppPreferenceManager;
import lt.marsrutai.mobile.android.manager.PreferenceDefaultValueResolvers;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.preference.PreferenceManager;

/**
 * Utility class for preference value retrieval
 *
 * @author Justas
 *
 */
public class PreferenceUtils {

    public static final String SCHEDULE_ACTIVITY_OPENED = "schedule_activity_opened";
    public static final String MAP_TYPE = "map_type";
    public static final String SELECTED_SCOPE_FOLDER = "selected_scope_folder";
    public static final String FASTEST_ROUTE_CHANGE_COUNT = "fastest_route_change_count";
    public static final String FASTEST_ROUTE_CHANGE_DURATION = "fastest_route_change_duration";
    public static final String FASTEST_ROUTE_WALK_DISTANCE = "fastest_route_walk_distance";
    public static final String FASTEST_ROUTE_WALK_SPEED = "fastest_route_walk_speed";
    public static final String FASTEST_ROUTE_TRANSPORT_TYPES = "fastest_route_transport_types";

    /**
     * <p>Resolves the preference with the provided key and casts it to the expected type.</p>
     * <p>If the preference is saved, it's value is fetched, otherwise a default value is returned</p>
     *
     * @param context Context
     * @param key Preference key
     * @return Current preference value if set, otherwise it's default value.
     * @see AppPreferenceManager#resolveDefaultValue(Context, String)
     */
    @SuppressWarnings("unchecked")
    public static <T> T getPreferenceValue(Context context, String key) {
        Object value = PreferenceManager.getDefaultSharedPreferences(context).getAll().get(key);

        // If none is currently set, resolve it's default
        return value == null ? PreferenceDefaultValueResolvers.<T>resolveDefaultValue(context, key) : (T) value;
    }

    /**
     * <p>Sets Boolean preference value.</p>
     *
     * @param context Context
     * @param key Preference key
     * @param value Preference value
     */
    public static void setBooleanPreferenceValue(Context context, String key, Boolean value) {
        PreferenceManager.getDefaultSharedPreferences(context).edit().putBoolean(key, value).commit();
    }

    /**
     * <p>Sets String preference value.</p>
     *
     * @param context Context
     * @param key Preference key
     * @param value Preference value
     */
    public static void setStringPreferenceValue(Context context, String key, String value) {
        PreferenceManager.getDefaultSharedPreferences(context).edit().putString(key, value).commit();
    }

    /**
     * <p>Sets {@link Integer} preference value.</p>
     *
     * @param context Context
     * @param key Preference key
     * @param value Preference value
     */
    public static void setIntegerPreferenceValue(Context context, String key, Integer value) {
        PreferenceManager.getDefaultSharedPreferences(context).edit().putInt(key, value).commit();
    }

    /**
     * Adds a value to a serializable map preference. The map is serialized and
     * saved as a string preference.
     * 
     * @param context
     * @param preferenceKey
     * @param entryKey
     * @param entryValue
     * @see #setSerializedPreference(Context, String, Object)
     * @see #getSerializedPreferenceMap(Context, String)
     */
    public static <K, V> void addSerializedMapPreferenceValue(Context context, String preferenceKey, K entryKey, V entryValue) {
        Map<K, V> preference = getSerializedPreferenceMap(context, preferenceKey);
        
        preference.put(entryKey, entryValue);
        setSerializedPreference(context, preferenceKey, preference);
    }

    /**
     * Removes a value from the serializable map preference. The map is
     * serialized and saved as a string preference.
     * 
     * @param context
     * @param preferenceKey
     * @param entryKey
     * @see #setSerializedPreference(Context, String, Object)
     * @see #getSerializedPreferenceMap(Context, String)
     */
    public static <K> void removeSerializedMapPreferenceValue(Context context, String preferenceKey, K entryKey) {
        Map<K, ?> preference = getSerializedPreferenceMap(context, preferenceKey);

        preference.remove(entryKey);
        setSerializedPreference(context, preferenceKey, preference);
    }

    /**
     * Serializes the provided value and stores it as a preference with a preferenceKey.
     * 
     * @param context
     * @param preferenceKey
     * @param value
     */
    public static <T> void setSerializedPreference(Context context, String preferenceKey, Object value) {
        String deflatedValue = Base64Utils.deflate(value);
        
        SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
        Editor editor = sharedPrefs.edit();
        editor.putString(preferenceKey, deflatedValue);
        editor.commit();
    }

    /**
     * Fetches a saved preference and deserializes it to a map.
     * 
     * @param context
     * @param preferenceKey
     * @return
     */
    public static <K, V> Map<K, V> getSerializedPreferenceMap(Context context, String preferenceKey) {
        String deflatedPreference = null;
        SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
        try {
            deflatedPreference = sharedPrefs.getString(preferenceKey, null);
        }
        catch (ClassCastException e) {
            e.printStackTrace();
        }

        Map<K, V> map = null;
        if (deflatedPreference == null) {
            map = new HashMap<K, V>();
        }
        else {
            map = Base64Utils.inflate(deflatedPreference);
        }

        return map;
    }
}
